/**
 * ****************************************************************************
 * Project: RoboBridge
 * ----------------------------------------------------------------------------
 * -------------------------- [c]2012 - KrawallMann ---------------------------
 * ---------------------- http://www.krawallmann.de.tc/ -----------------------
 * ****************************************************************************
 * File: AbstractCommunicationInterface.java Package:
 * tc.de.krawallmann.robobridge.communication Version: 1.0 Author(s):
 * KrawallMann
 * ****************************************************************************
 * Description:
 * ****************************************************************************
 */
package tc.de.krawallmann.robobridge.communication;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

import tc.de.krawallmann.robobridge.util.Exceptions;

/**
 * The Class AbstractCommunicationInterface is an abstract class containing
 * methods for I/O.
 * 
 * @param <T>
 *            the generic type
 * @author KrawallMann
 * @version 1.0
 */
public abstract class AbstractCommunicationInterface<T extends AbstractRemoteCommunicationDevice> {

	public static final int NORMAL=0;
	public static final int ERROR=1;
	/** The listeners. */
	protected transient final Set<ConnectionListener<T>> listeners =
			new HashSet<ConnectionListener<T>>();

	/** The local device. */
	protected transient final AbstractLocalCommunicationDevice localDevice;

	/** The reader. */
	protected transient final Reader reader;

	/** The writer. */
	protected transient final Writer writer;
	private long startTime;

	/**
	 * Instantiates a new abstract communication interface.
	 * 
	 * @param localDevice
	 *            the local device
	 * @param reader
	 *            the reader
	 * @param writer
	 *            the writer
	 */
	public AbstractCommunicationInterface(final AbstractLocalCommunicationDevice localDevice,
			final Reader reader, final Writer writer) {
		super();
		if (localDevice == null) {
			throw Exceptions.onNullPointer(this, "localDevice");
		}
		if (reader == null) {
			throw Exceptions.onNullPointer(this, "reader");
		}
		if (writer == null) {
			throw Exceptions.onNullPointer(this, "writer");
		}
		this.localDevice = localDevice;
		this.reader = reader;
		this.writer = writer;
	}

	/**
	 * Adds the connection listener.
	 * 
	 * @param listener
	 *            the listener
	 * @return true, if successful
	 */
	public boolean addConnectionListener(final ConnectionListener<T> listener) {
		return this.listeners.add(listener);
	}

	/**
	 * Close.
	 */
	public abstract void close(int reason);

	/**
	 * Connect.
	 * 
	 * @param device
	 *            the device
	 * @throws IOException
	 *             Signals that an I/O exception has occurred.
	 */
	public abstract void connect(T device) throws IOException;

	/**
	 * Gets the connected device.
	 * 
	 * @return the connected device
	 */
	public abstract T getConnectedDevice();

	/**
	 * Gets the device scanner.
	 * 
	 * @return the device scanner
	 */
	public abstract AbstractDeviceScanner<T> getDeviceScanner();

	/**
	 * Gets the local device.
	 * 
	 * @return the local device
	 */
	public AbstractLocalCommunicationDevice getLocalDevice() {
		return localDevice;
	}

	/**
	 * Gets the reader.
	 * 
	 * @return the reader
	 */
	public Reader getReader() {
		return reader;
	}

	/**
	 * Gets the writer.
	 * 
	 * @return the writer
	 */
	public Writer getWriter() {
		return writer;
	}

	/**
	 * Checks if is connected.
	 * 
	 * @return true, if is connected
	 */
	public abstract boolean isConnected();

	/**
	 * Removes the connection listener.
	 * 
	 * @param listener
	 *            the listener
	 * @return true, if successful
	 */
	public boolean removeConnectionListener(final ConnectionListener<T> listener) {
		return this.listeners.remove(listener);
	}

	/**
	 * Start scan.
	 * 
	 * @throws IOException
	 *             Signals that an I/O exception has occurred.
	 */
	public abstract void startScan() throws IOException;

	/**
	 * Stop scan.
	 */
	public abstract void stopScan();

	public long getStartTime() {
		return startTime;
	}

	protected void setStartTime(long startTime) {
		this.startTime = startTime;
	}
}
